import math
import numpy as np
import torch
device = "cuda:0" if torch.cuda.is_available() else "cpu"
   
import torch
from torchvision.ops import batched_nms


def get_max_confidence_box(boxes, scores):
    """
    使用 torch.argmax 选择置信度最高的检测框
    :param boxes: 检测框，形状为 (N, 4)，表示 [x1, y1, x2, y2]
    :param scores: 检测框的置信度，形状为 (N,)
    :return: 置信度最高的检测框的索引
    """
    max_index = torch.argmax(scores)
    return max_index


def apply_nms(boxes, scores, iou_threshold=0.5):
    """
    使用 NMS 算法选择合适的检测框
    :param boxes: 检测框，形状为 (N, 4)，表示 [x1, y1, x2, y2]
    :param scores: 检测框的置信度，形状为 (N,)
    :param iou_threshold: IOU 阈值，用于判断检测框是否重叠
    :return: 经过 NMS 筛选后的检测框的索引
    """
    keep_indices = batched_nms(boxes, scores, torch.zeros_like(scores), iou_threshold)
    return keep_indices


def test_nms():
    # # 检测框，每个框表示 [x1, y1, x2, y2]
    # boxes = torch.tensor([
    #     [10, 10, 60, 60],  # 框 A
    #     [12, 12, 58, 58],  # 框 B
    #     [20, 20, 70, 70]   # 框 C
    # ], dtype=torch.float32)

    # # 检测框的置信度（相似度）
    # scores = torch.tensor([0.8, 0.9, 0.85], dtype=torch.float32)
    boxes = torch.tensor([
        [10, 10, 50, 50],  # 框A，索引0
        [10, 10, 50, 50],  # 框B，索引1（与框A完全重叠）
    ], dtype=torch.float32)
    scores = torch.tensor([0.8, 0.9])
    keep_indices = apply_nms(boxes, scores, iou_threshold=0.95)


    # 使用 torch.argmax 选择置信度最高的检测框
    max_index = get_max_confidence_box(boxes, scores)
    print("使用 torch.argmax 选择的检测框索引:", max_index)
    print("对应的检测框:", boxes[max_index])

    # 使用 NMS 算法选择合适的检测框
    keep_indices = apply_nms(boxes, scores, iou_threshold=0.8)
    print("使用 NMS 算法选择的检测框索引:", keep_indices)
    print("对应的检测框:", boxes[keep_indices])


import torchvision.ops as ops
def density_weighted_nms(boxes, scores, iou_threshold=0.5, alpha=0.5):
    """
    基于密度加权的NMS算法：
    - boxes: 候选框坐标，格式为[B, N, 4]（x1, y1, x2, y2）
    - scores: 置信度，格式为[B, N]
    - iou_threshold: 传统NMS的IoU阈值
    - alpha: 置信度与定位质量的平衡系数（0~1）
    - density_threshold: 判定为密集区域的候选框数量阈值
    """
    # Step 1: 计算每个框的定位质量（此处以周围框密度为例）
    density, density_indices = calculate_density(boxes, iou_threshold)
    density_scores = scores[density_indices]
    
    # Step 2: 计算综合评分（置信度 + 密度权重）
    # 定位质量越高（密度越大），权重越高
    combined_scores = alpha * scores + (1 - alpha) * density_scores
    
    # # Step 3: 按综合评分重新排序
    # sorted_indices = torch.argsort(combined_scores, descending=True)
    # sorted_boxes = boxes[sorted_indices]
    # sorted_scores = combined_scores[sorted_indices]
    
    # Step 4: 执行传统NMS，但基于新的排序
    keep_indices = ops.nms(boxes, combined_scores, iou_threshold)
    
    # 还原原始索引
    # final_keep = sorted_indices[keep_indices]
    return keep_indices, combined_scores

# def calculate_density(boxes, scores, iou_threshold):
#     """
#     计算每个框周围的重叠框数量（密度）
#     """
#     N = boxes.shape[0]
#     density = torch.zeros(N, device=boxes.device)
    
#     # 计算所有框的IoU矩阵
#     iou_matrix = ops.box_iou(boxes, boxes)
    
#     # 对每个框，统计IoU超过阈值的邻居数量
#     for i in range(N):
#         density[i] = (iou_matrix[i] > iou_threshold).sum() - 1  # 排除自身
    
    
#     return density / N

# def calculate_density(boxes, iou_threshold=0.5):
#     """
#     计算每个框与周围框的最大重叠度（密度）
#     """
#     N = boxes.shape[0]
#     density = torch.zeros(N, device=boxes.device)
#     density_indices = torch.zeros(N, device=boxes.device, dtype=torch.int64)
#     # 计算所有框的IoU矩阵
#     iou_matrix = ops.box_iou(boxes, boxes)
    
#     # 对每个框，找出与其重叠度超过阈值的邻居的最大重叠度
#     for i in range(N):
#         # 获取第i个框与所有框的IoU值，并排除自身
#         iou_values = iou_matrix[i, :].clone()
#         iou_values[i] = 0  # 排除自身
        
#         # 过滤出IoU值超过阈值的邻居
#         # valid_iou_values = iou_values[iou_values > iou_threshold]
#         valid_iou_indices = torch.nonzero(iou_values > iou_threshold).reshape(-1)
#         valid_iou_values = iou_values[valid_iou_indices]
#         # 如果有超过阈值的邻居，则取最大值，否则取0
#         if valid_iou_values.numel() > 0:
#             density_indices[i] = valid_iou_indices[torch.argmax(valid_iou_values)]
#             density[i] = iou_values[density_indices[i]]
#         else:
#             density[i] = 0
    
#     return density, density_indices

def calculate_density(boxes, iou_threshold=0.5):
    """
    计算每个框与周围框的最大重叠度（密度）
    """
    N = boxes.shape[0]
    density = torch.zeros(N, device=boxes.device)
    density_indices = torch.zeros(N, device=boxes.device, dtype=torch.int64)

    # 计算所有框的IoU矩阵
    iou_matrix = ops.box_iou(boxes, boxes)

    # 将对角线上的IoU值置为0，排除自身
    torch.diagonal(iou_matrix).zero_()

    # 找到每个框的IoU值超过阈值的邻居的最大重叠度
    valid_iou_mask = iou_matrix > iou_threshold
    # 如果没有超过阈值的邻居，则使用0填充
    density_scores = torch.where(valid_iou_mask, iou_matrix, torch.zeros_like(iou_matrix))
    # 计算每行的最大值
    density, density_indices = torch.max(density_scores, dim=1)

    return density, density_indices

def NMS(boxes, scores, iou_threshold, class_nms='CIoU'):
    # 初始化不同的IoU (Intersection over Union) 类型标志
    GIoU = CIoU = DIoU = EIoU = SIoU = False

    # 根据 class_nms 参数选择要使用的 IoU 类型
    if class_nms == 'CIoU':
        CIoU = True
    elif class_nms == 'DIoU':
        DIoU = True
    elif class_nms == 'GIoU':
        GIoU = True
    # elif class_nms == 'EIoU':
    #     EIoU = True
    # else:
    #     SIoU = True

    # 根据分数对边界框索引进行排序（从高到低）
    B = torch.argsort(scores, dim=-1, descending=True)

    # 存储最终选定的边界框索引
    keep = []

    while B.numel() > 0:
        # 选择分数最高的边界框的索引
        index = B[0]
        # 将该索引添加到最终保留的列表中
        keep.append(index)
        if B.numel() == 1:
            break

        # 计算当前边界框与其余边界框的IoU
        iou = bbox_iou_extend(boxes[index, :], boxes[B[1:], :], GIoU=GIoU, DIoU=DIoU, CIoU=CIoU)
        # 找到IoU小于等于指定阈值的边界框索引
        inds = torch.nonzero(iou <= iou_threshold).reshape(-1)
        # 更新B以排除已经被选择的边界框
        B = B[inds + 1]

    # 返回最终选定的边界框索引作为结果
    return torch.tensor(keep)

def bbox_iou_extend(box1, box2, xywh=True, GIoU=False, DIoU=False, CIoU=False, eps=1e-7):
    """
    Calculates IoU, GIoU, DIoU, or CIoU between two boxes, supporting xywh/xyxy formats.

    Input shapes are box1(1,4) to box2(n,4).
    """
    # Get the coordinates of bounding boxes
    if xywh:  # transform from xywh to xyxy
        (x1, y1, w1, h1), (x2, y2, w2, h2) = box1.chunk(4, -1), box2.chunk(4, -1)
        w1_, h1_, w2_, h2_ = w1 / 2, h1 / 2, w2 / 2, h2 / 2
        b1_x1, b1_x2, b1_y1, b1_y2 = x1 - w1_, x1 + w1_, y1 - h1_, y1 + h1_
        b2_x1, b2_x2, b2_y1, b2_y2 = x2 - w2_, x2 + w2_, y2 - h2_, y2 + h2_
    else:  # x1, y1, x2, y2 = box1
        b1_x1, b1_y1, b1_x2, b1_y2 = box1.chunk(4, -1)
        b2_x1, b2_y1, b2_x2, b2_y2 = box2.chunk(4, -1)
        w1, h1 = b1_x2 - b1_x1, (b1_y2 - b1_y1).clamp(eps)
        w2, h2 = b2_x2 - b2_x1, (b2_y2 - b2_y1).clamp(eps)

    # Intersection area
    inter = (b1_x2.minimum(b2_x2) - b1_x1.maximum(b2_x1)).clamp(0) * (
        b1_y2.minimum(b2_y2) - b1_y1.maximum(b2_y1)
    ).clamp(0)

    # Union Area
    union = w1 * h1 + w2 * h2 - inter + eps

    # IoU
    iou = inter / union
    if CIoU or DIoU or GIoU:
        cw = b1_x2.maximum(b2_x2) - b1_x1.minimum(b2_x1)  # convex (smallest enclosing box) width
        ch = b1_y2.maximum(b2_y2) - b1_y1.minimum(b2_y1)  # convex height
        if CIoU or DIoU:  # Distance or Complete IoU https://arxiv.org/abs/1911.08287v1
            c2 = cw**2 + ch**2 + eps  # convex diagonal squared
            rho2 = ((b2_x1 + b2_x2 - b1_x1 - b1_x2) ** 2 + (b2_y1 + b2_y2 - b1_y1 - b1_y2) ** 2) / 4  # center dist ** 2
            if CIoU:  # https://github.com/Zzh-tju/DIoU-SSD-pytorch/blob/master/utils/box/box_utils.py#L47
                v = (4 / math.pi**2) * (torch.atan(w2 / h2) - torch.atan(w1 / h1)).pow(2)
                with torch.no_grad():
                    alpha = v / (v - iou + (1 + eps))
                return iou - (rho2 / c2 + v * alpha)  # CIoU
            return iou - rho2 / c2  # DIoU
        c_area = cw * ch + eps  # convex area
        return iou - (c_area - union) / c_area  # GIoU https://arxiv.org/pdf/1902.09630.pdf
    return iou  # IoU


def box_iou(box1, box2, eps=1e-7):
    # https://github.com/pytorch/vision/blob/master/torchvision/ops/boxes.py
    """
    Return intersection-over-union (Jaccard index) of boxes.

    Both sets of boxes are expected to be in (x1, y1, x2, y2) format.

    Arguments:
        box1 (Tensor[N, 4])
        box2 (Tensor[M, 4])

    Returns:
        iou (Tensor[N, M]): the NxM matrix containing the pairwise
            IoU values for every element in boxes1 and boxes2
    """
    # inter(N,M) = (rb(N,M,2) - lt(N,M,2)).clamp(0).prod(2)
    (a1, a2), (b1, b2) = box1.unsqueeze(1).chunk(2, 2), box2.unsqueeze(0).chunk(2, 2)
    inter = (torch.min(a2, b2) - torch.max(a1, b1)).clamp(0).prod(2)

    # IoU = inter / (area1 + area2 - inter)
    return inter / ((a2 - a1).prod(2) + (b2 - b1).prod(2) - inter + eps)


def bbox_ioa(box1, box2, eps=1e-7):
    """
    Returns the intersection over box2 area given box1, box2.

    Boxes are x1y1x2y2
    box1:       np.array of shape(4)
    box2:       np.array of shape(nx4)
    returns:    np.array of shape(n)
    """
    # Get the coordinates of bounding boxes
    b1_x1, b1_y1, b1_x2, b1_y2 = box1
    b2_x1, b2_y1, b2_x2, b2_y2 = box2.T

    # Intersection area
    inter_area = (np.minimum(b1_x2, b2_x2) - np.maximum(b1_x1, b2_x1)).clip(0) * (
        np.minimum(b1_y2, b2_y2) - np.maximum(b1_y1, b2_y1)
    ).clip(0)

    # box2 area
    box2_area = (b2_x2 - b2_x1) * (b2_y2 - b2_y1) + eps

    # Intersection over box2 area
    return inter_area / box2_area


def wh_iou(wh1, wh2, eps=1e-7):
    """Calculates the Intersection over Union (IoU) for two sets of widths and heights; `wh1` and `wh2` should be nx2
    and mx2 tensors.
    """
    wh1 = wh1[:, None]  # [N,1,2]
    wh2 = wh2[None]  # [1,M,2]
    inter = torch.min(wh1, wh2).prod(2)  # [N,M]
    return inter / (wh1.prod(2) + wh2.prod(2) - inter + eps)  # iou = inter / (area1 + area2 - inter)


import torch
import torch.nn as nn
import numpy as np

def softer_nms(dets, scores, sigma=0.5, score_thresh=0.001, max_dets=300):
    """
    Softer-NMS 实现
    
    参数:
        dets (Tensor): 边界框坐标，格式为 [x1, y1, x2, y2] (shape: [N, 4])
        scores (Tensor): 边界框的置信度 (shape: [N])
        sigma (float): 高斯加权标准差，控制权重衰减速度
        score_thresh (float): 保留框的最低置信度阈值
        max_dets (int): 最大保留框数量
    
    返回:
        keep (Tensor): 保留的框的索引
    """
    x1 = dets[:, 0]
    y1 = dets[:, 1]
    x2 = dets[:, 2]
    y2 = dets[:, 3]
    
    areas = (x2 - x1 + 1) * (y2 - y1 + 1)
    order = scores.argsort(descending=True)  # 按置信度降序排序
    
    keep = []
    while order.numel() > 0:
        if len(keep) >= max_dets:
            break
        
        i = order[0]
        keep.append(i)
        
        if order.numel() == 1:
            break
        
        # 计算当前框与其他框的IoU
        xx1 = torch.maximum(x1[i], x1[order[1:]])
        yy1 = torch.maximum(y1[i], y1[order[1:]])
        xx2 = torch.minimum(x2[i], x2[order[1:]])
        yy2 = torch.minimum(y2[i], y2[order[1:]])
        
        w = torch.clamp(xx2 - xx1 + 1, min=0)
        h = torch.clamp(yy2 - yy1 + 1, min=0)
        inter = w * h
        iou = inter / (areas[i] + areas[order[1:]] - inter)
        
        # 计算高斯权重（重叠越高的框权重越大）
        weights = torch.exp(-(iou**2) / sigma)
        
        # 更新剩余框的坐标（加权平均）
        x1[order[1:]] = weights * x1[order[1:]] + (1 - weights) * x1[i]
        y1[order[1:]] = weights * y1[order[1:]] + (1 - weights) * y1[i]
        x2[order[1:]] = weights * x2[order[1:]] + (1 - weights) * x2[i]
        y2[order[1:]] = weights * y2[order[1:]] + (1 - weights) * y2[i]
        
        # 更新置信度（衰减重叠框的分数）
        scores[order[1:]] *= weights
        
        # 移除置信度低于阈值的框
        idx = torch.where(scores[order[1:]] >= score_thresh)[0]
        order = order[idx + 1]  # +1 因为 order[1:] 的索引偏移
    
    return torch.tensor(keep, dtype=torch.long), scores, dets


def iou_guided_nms(dets, cls_scores, iou_scores, iou_thresh=0.5):
    combined_scores = cls_scores * iou_scores  # 综合得分
    order = combined_scores.argsort(descending=True)
    keep = []
    while order.numel() > 0:
        i = order[0]
        keep.append(i)
        iou = bbox_iou(dets[i].unsqueeze(0), dets[order[1:]])
        idx = torch.where(iou < iou_thresh)[0]
        order = order[idx + 1]
    return keep

def bbox_iou(box1, box2):
    """
    计算两个边界框之间的IoU
    Args:
        box1: [x1, y1, x2, y2]
        box2: [x1, y1, x2, y2]
    Returns:
        iou: 交并比
    """
    # 计算交集区域的坐标
    x1 = torch.max(box1[0], box2[0])
    y1 = torch.max(box1[1], box2[1])
    x2 = torch.min(box1[2], box2[2])
    y2 = torch.min(box1[3], box2[3])
    
    # 计算交集区域面积
    inter_area = torch.clamp(x2 - x1, min=0) * torch.clamp(y2 - y1, min=0)
    
    # 计算两个框各自的面积
    box1_area = (box1[2] - box1[0]) * (box1[3] - box1[1])
    box2_area = (box2[2] - box2[0]) * (box2[3] - box2[1])
    
    # 计算并集面积
    union_area = box1_area + box2_area - inter_area
    
    # 计算IoU
    iou = inter_area / union_area
    return iou

def nmw(boxes, scores, iou_threshold=0.5, score_threshold=0.01):
    """
    Non-Maximum Weighting (NMW) 实现
    Args:
        detections: 边界框和置信度，形状为[N,5](x1,y1,x2,y2,score)
        iou_threshold: IoU阈值
        score_threshold: 置信度阈值
    Returns:
        weighted_boxes: 加权后的边界框，形状为[M,4]
        weighted_scores: 加权后的置信度，形状为[M]
    """
    if len(boxes) == 0:
        return None, None
    
    # 按置信度排序
    order = torch.argsort(scores, descending=True)
    boxes = boxes[order]
    scores = scores[order]
    
    keep_boxes = []
    keep_scores = []
    
    while len(boxes) > 0:
        # 选择当前最高分的框
        best_box = boxes[0]
        best_score = scores[0]
        
        # 计算与其它框的IoU
        ious = torch.tensor([bbox_iou(best_box, box) for box in boxes])
        
        # 选择IoU大于阈值的框(包括自己)
        mask = ious >= iou_threshold
        selected_boxes = boxes[mask]
        selected_scores = scores[mask]
        selected_ious = ious[mask]
        
        # 计算权重: w_i = C_i * iou(B_i, B_max)
        weights = selected_scores * selected_ious
        
        # 加权平均坐标
        weighted_box = torch.sum(selected_boxes * weights.unsqueeze(1), dim=0) / torch.sum(weights)
        
        # 加权平均分数(可选)
        weighted_score = torch.sum(selected_scores * weights) / torch.sum(weights)
        
        # 保留结果
        if weighted_score >= score_threshold:
            keep_boxes.append(weighted_box)
            keep_scores.append(weighted_score)
        
        # 移除已处理的框
        boxes = boxes[~mask]
        scores = scores[~mask]
    
    if len(keep_boxes) > 0:
        return torch.stack(keep_boxes), torch.stack(keep_scores)
    else:
        return torch.zeros((0, 4)), torch.zeros(0)

# import torch

# def adaptive_nms(boxes, scores, densities, nms_threshold=0.5, score_threshold=0.01):
#     """
#     Adaptive Non-Maximum Suppression实现
    
#     参数:
#         boxes (Tensor[N, 4]): 边界框坐标，格式为(x1, y1, x2, y2)
#         scores (Tensor[N]): 检测得分
#         densities (Tensor[N]): 密度预测值，范围[0,1]
#         nms_threshold (float): 基础抑制阈值(默认0.5)
#         score_threshold (float): 分数过滤阈值(默认0.01)
    
#     返回:
#         keep (Tensor): 保留的检测框索引
#     """
#     # 过滤低分检测框
#     keep_mask = scores > score_threshold
#     boxes = boxes[keep_mask]
#     scores = scores[keep_mask]
#     densities = densities[keep_mask]
    
#     # 按得分降序排序
#     sorted_indices = torch.argsort(scores, descending=True)
#     boxes = boxes[sorted_indices]
#     scores = scores[sorted_indices]
#     densities = densities[sorted_indices]
    
#     # 计算每个框的面积
#     x1, y1, x2, y2 = boxes.unbind(1)
#     areas = (x2 - x1) * (y2 - y1)
    
#     keep = []
#     while sorted_indices.numel() > 0:
#         # 取当前最高分框
#         i = sorted_indices.pop()
#         keep.append(i.item())
#         sorted_indices = sorted_indices[1:]  # 移除第一个元素
        
#         if sorted_indices.size(0) == 1:
#             break
            
#         # 计算动态阈值
#         current_density = densities[0]
#         adaptive_thresh = max(nms_threshold, current_density.item())
        
#         # 计算IoU
#         current_box = boxes[0]
#         other_boxes = boxes[1:]
        
#         xx1 = torch.max(current_box[0], other_boxes[:, 0])
#         yy1 = torch.max(current_box[1], other_boxes[:, 1])
#         xx2 = torch.min(current_box[2], other_boxes[:, 2])
#         yy2 = torch.min(current_box[3], other_boxes[:, 3])
        
#         w = torch.clamp(xx2 - xx1, min=0)
#         h = torch.clamp(yy2 - yy1, min=0)
#         inter = w * h
        
#         current_area = areas[0]
#         other_areas = areas[1:]
#         union = current_area + other_areas - inter
#         iou = inter / union
        
#         # 根据动态阈值筛选保留框
#         mask = iou < adaptive_thresh
#         mask = torch.cat([torch.tensor([True], device=mask.device), mask])
        
#         # 更新索引
#         sorted_indices = sorted_indices[mask]
#         boxes = boxes[mask]
#         scores = scores[mask]
#         densities = densities[mask]
#         areas = areas[mask]
        
#     return torch.tensor(keep, dtype=torch.long)

def adaptive_nms(boxes, scores, density_pred, max_threshold=0.7, base_threshold=0.5):
    """
    :param boxes:       预测框坐标 (N,4) [x1,y1,x2,y2]
    :param scores:     预测得分 (N,)
    :param density_pred: 密度预测值 (N,)
    :return:            保留的索引
    """
    # 按得分降序排序
    order = scores.argsort(descending=True)
    boxes = boxes[order]
    scores = scores[order]
    density_pred = density_pred[order]

    keep = []
    while order.size(0) > 0:
        # 取当前最高分框
        idx = order[0]
        keep.append(idx.item())
        
        if order.size(0) == 1:
            break
            
        # 核心逻辑：动态阈值计算
        current_density = torch.clamp(density_pred[0], min=base_threshold, max=max_threshold)
        adaptive_thresh = max(base_threshold, current_density.item())
        
        # 计算当前框与其他框的IoU
        current_box = boxes[0:1]
        other_boxes = boxes[1:]
        iou = box_iou(current_box, other_boxes).squeeze(0)
        
        # 筛选保留框 (IoU < 阈值)
        mask = iou < adaptive_thresh
        mask = torch.cat([torch.tensor([False], device=mask.device), mask])
        
        # 更新待处理数据
        order = order[mask]
        boxes = boxes[mask]
        scores = scores[mask]
        density_pred = density_pred[mask]
        
    return torch.tensor(keep)


# 假设输入数据
boxes = torch.tensor([[10, 10, 50, 50], [12, 12, 48, 48], [100, 100, 150, 150], [101, 101, 151, 150], [102, 100, 151, 150]], dtype=torch.float32)
scores = torch.tensor([0.9, 0.8, 0.85, 0.84, 0.88])  # 最高置信度框（index 0）定位不准

# boxes = torch.tensor([[10, 10, 50, 50], [11, 11, 51, 50], [12, 12, 48, 48], [100, 100, 150, 150], [101, 101, 151, 150], [102, 100, 151, 150]], dtype=torch.float32)
# scores = torch.tensor([0.9, 0.8, 0.8, 0.85, 0.84, 0.88])  # 最高置信度框（index 0）定位不准

# 使用 NMS 算法选择合适的检测框
keep_indices = NMS(boxes, scores, iou_threshold=0.5)
print("使用 NMS 算法选择的检测框索引:", keep_indices)
print(f"r={scores[keep_indices[1]]/scores[keep_indices[0]]}")
# 执行改进的NMS
keep, combined_scores = density_weighted_nms(boxes, scores, iou_threshold=0.3, alpha=0.6)
print(f"combined_scores={combined_scores}")
print("使用 improved NMS 算法选择的检测框索引:", keep)  # 可能保留index 1（次高置信度但密度更高）
print(f"r={scores[keep[1]]/scores[keep[0]]}")

# 执行 softer-NMS
keep, new_scores, dets = softer_nms(boxes, scores, sigma=0.5, score_thresh=0.001, max_dets=300)
print("使用 softer NMS 算法选择的检测框索引:", keep)  # 可能保留index 1（次高置信度但密度更高）
print(f"new_scores={new_scores}")
print(f"dets={dets}")
print(f"r={scores[keep[1]]/scores[keep[0]]}")

# weighted_nms
weighted_boxes, weighted_scores = nmw(boxes, scores, iou_threshold=0.5, score_threshold=0.01)
print("使用 weighted NMS 算法选择的检测框索引:", weighted_boxes)  # 可能保留index 1（次高置信度但密度更高）
print(f"weighted_scores={weighted_scores}")

# adaptive_nms
densities, density_indices = calculate_density(boxes, iou_threshold=0.5)
print(f"densities={densities}")
# keep = adaptive_nms(boxes, scores, densities, nms_threshold=0.5, score_threshold=0.01)
keep = adaptive_nms(boxes, scores, densities,max_threshold=0.5, base_threshold=0.3)
print("使用 adaptive NMS 算法选择的检测框索引:", keep)  # 可能保留index 1（次高置信度但密度更高）
